package com.lian.chatroom.client;

import com.lian.chatroom.message.*;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 自定义处理器，先继承ChannelInboundHandlerAdapter，这是一个入站处理器
 */
@Slf4j
public class ClientHandler extends ChannelInboundHandlerAdapter {

    //CountDownLatch是一个同步工具类，用来协调多个线程之间的同步，当计数器数值减为0时，
    // 所有受其影响而等待的线程将会被激活，这样保证模拟并发请求的真实性,否则就await阻塞
    //保安大爷必须等学校孩子线程都出来后，才会执行锁门线程
    CountDownLatch WAIT_FOR_LOGIN = new CountDownLatch(1);
    //表示暂未登录,AtomicBoolean保证在高并发的情况下只有一个线程能够访问这个属性值
    AtomicBoolean LOGIN = new AtomicBoolean(false);

    /**
     * 接收服务端发送过来的消息
     * 1、客户端与服务器通道连接成功后，就会触发Active事件，服务端登录后，返回登录状态的信息，就会触发channelRead事件
     * @param ctx
     * @param msg 服务器返回来的数据，Response类，例如登录成功或失败返回的消息
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.debug("msg:{}",msg);
        if (msg instanceof LoginResponseMessage){
            LoginResponseMessage response = (LoginResponseMessage) msg;
            if (response.isSuccess()){
                LOGIN.set(true);
            }
        }
        //当服务端响应回客户端时，计数操作减1
        WAIT_FOR_LOGIN.countDown();
    }

    /**
     * 客户端和服务器端连接建立后，会触发此事件
     * 客户端就可以给服务端发送消息了
     * 登录需求就在此实现
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        /**
         * 1、新建线程，负责接收用户在客户端的输入，负责向服务端发送各种消息
         * 新线程与netty的线程没有关联，可以独立的接收用户在客户端的输入
         * 如果不创建新线程，之后接收和发送消息都是用的EventLoopGroup里的nio线程
         */
        new Thread(()->{
            //新建一个Scanner客户端扫描器
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入用户名: ");
            String username = scanner.nextLine();
            System.out.println("请输入密码: ");
            String password = scanner.nextLine();
            //构造消息对象
            LoginRequestMessage message = new LoginRequestMessage(username, password);
            //发送消息对象到通道里
            ctx.writeAndFlush(message);
            //用户输入完账号密码后，就阻塞等待服务器响应
            System.out.println("等待后续操作...");
            //当计数不为0时，就阻塞住，等待服务端响应
            try {
                WAIT_FOR_LOGIN.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //如果登录失败
            if (!LOGIN.get()) {
                //关闭通道
                ctx.channel().close();
                //线程结束方法
                return;
            }
            //如果登陆成功，应该打印一个菜单，选择后续的功能，比如聊天等
            while (true){
                System.out.println("===============功能菜单===============");
                System.out.println("send [username] [content]");            //单聊
                System.out.println("gsend [group name] [content]");         //群聊
                System.out.println("gcreate [group name] [m1,m2,m3...]");   //群创建
                System.out.println("gmembers [group name]");                //获取群成员
                System.out.println("gjoin [group name]");                   //加入群聊
                System.out.println("gquit [group name]");                   //退出群聊
                System.out.println("quit");                                 //退出客户端程序
                System.out.println("==================================");
                String commond = scanner.nextLine();
                String[] s = commond.split(" ");
                //以命令作为判断
                switch (s[0]){
                    case "send":
                        //发送一条聊天消息
                        ctx.writeAndFlush(new ChatRequestMessage(username,s[1],s[2]));
                        break;
                    case "gsend":
                        ctx.writeAndFlush(new GroupChatRequestMessage(username,s[1],s[2]));
                        break;
                    case "gcreate":
                        Set<String> members = new HashSet<>(Arrays.asList(s[2].split(",")));
                        members.add(username);  //加入建群人自己
                        ctx.writeAndFlush(new GroupCreateRequestMessage(s[1],members));
                        break;
                    case "gmembers":
                        ctx.writeAndFlush(new GroupMembersRequestMessage(s[1]));
                        break;
                    case "gjoin":
                        ctx.writeAndFlush(new GroupJoinRequestMessage(username,s[1]));
                        break;
                    case "gquit":
                        ctx.writeAndFlush(new GroupQuitRequestMessage(username,s[1]));
                        break;
                    //连接建立会触发Active事件，连接断开会触发InActive事件
                    //退出分为正常退出和异常退出，正常退出触发InActive事件，异常退出触发Exception事件
                    case "quit":
                        ctx.channel().close();
                        return;
                }

            }
        },"system in").start();
    }

    /**
     * 正常退出触发此事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
    }

}
